/********************************************************************
	Copyright (C) 2006-2008 Lensow
	http://www.lensow.com
	Created:	2008/06/07   10:46
	Filename: 	x:\Lensow\Loplayer\src\libcore\FGFilter.h
	Author:		Dean

	Purpose:
*********************************************************************/

#pragma once

#define MERIT64(merit) (((UINT64)(merit))<<16)
#define MERIT64_DO_NOT_USE MERIT64(MERIT_DO_NOT_USE)
#define MERIT64_DO_USE MERIT64(MERIT_DO_NOT_USE+1)
#define MERIT64_UNLIKELY (MERIT64(MERIT_UNLIKELY))
#define MERIT64_NORMAL (MERIT64(MERIT_NORMAL))
#define MERIT64_PREFERRED (MERIT64(MERIT_PREFERRED))
#define MERIT64_ABOVE_DSHOW (MERIT64(1)<<32)


class CFGFilter
{

public:
	CFGFilter(const CLSID& clsid, LPCWSTR name = L"", UINT64 merit = MERIT64_DO_USE);
	virtual ~CFGFilter() {}

	REFCLSID GetCLSID() const {
		return m_clsid;
	}
	const CComBSTR& GetName() const {
		return m_name;
	}
	UINT64 GetMerit() const {
		return m_merit.val;
	}
	DWORD GetMeritForDirectShow() {
		return m_merit.mid;
	}
	const CAtlList<GUID>& GetTypes() const;
	void SetTypes(const CAtlList<GUID>& types);
	void AddType(const GUID& majortype, const GUID& subtype);
	bool CheckTypes(const CAtlArray<GUID>& types, bool fExactMatch);

	CAtlList<CString> m_protocols, m_extensions, m_chkbytes; // TODO: subtype?

	virtual HRESULT Create(IBaseFilter** ppBF, CInterfaceList<IUnknown, &IID_IUnknown>& pUnks) = 0;
protected:
	CLSID m_clsid;
	CComBSTR m_name;
	struct {
		union {UINT64 val;
			struct {UINT64 low: 16,mid: 32, high:16;};
		};
	} m_merit;
	CAtlList<GUID> m_types;
};

class CFGFilterRegistry : public CFGFilter
{

public:
	CFGFilterRegistry(IMoniker* pMoniker, UINT64 merit = MERIT64_DO_USE);
	CFGFilterRegistry(LPCWSTR DisplayName, UINT64 merit = MERIT64_DO_USE);
	CFGFilterRegistry(const CLSID& clsid, UINT64 merit = MERIT64_DO_USE);

	const CString& GetDisplayName() const {
		return m_DisplayName;
	}
	IMoniker* GetMoniker() {
		return m_pMoniker;
	}

	HRESULT Create(IBaseFilter** ppBF, CInterfaceList<IUnknown, &IID_IUnknown>& pUnks);
protected:
	CString m_DisplayName;
	CComPtr<IMoniker> m_pMoniker;

	void ExtractFilterData(BYTE* p, UINT len);
};

template<class T>
class CFGFilterInternal : public CFGFilter
{
public:
	CFGFilterInternal(LPCWSTR name = L"", UINT64 merit = MERIT64_DO_USE) : CFGFilter(__uuidof(T), name, merit) {}

	HRESULT Create(IBaseFilter** ppBF, CInterfaceList<IUnknown, &IID_IUnknown>& pUnks) {
		CheckPointer(ppBF, E_POINTER);

		HRESULT hr = S_OK;
		CComPtr<IBaseFilter> pBF = new T(NULL, &hr);
		if (FAILED(hr)) return hr;

		*ppBF = pBF.Detach();

		return hr;
	}
};

class CFGFilterFile : public CFGFilter
{
public:
	CFGFilterFile(const CLSID& clsid, LPCTSTR path, LPCWSTR name = L"", UINT64 merit = MERIT64_DO_USE);

	HRESULT Create(IBaseFilter** ppBF, CInterfaceList<IUnknown, &IID_IUnknown>& pUnks);
protected:
	CString m_path;
	HINSTANCE m_hInst;
};

class CFGFilterVideoRenderer : public CFGFilter
{

public:
	CFGFilterVideoRenderer(HWND hWnd, const CLSID& clsid, LPCWSTR name = L"", UINT64 merit = MERIT64_DO_USE);

	HRESULT Create(IBaseFilter** ppBF, CInterfaceList<IUnknown, &IID_IUnknown>& pUnks);
protected:
	HWND m_hWnd;
};

class CFGFilterList
{
public:
	CFGFilterList();
	virtual ~CFGFilterList();

	bool IsEmpty() const {
		return m_filters.IsEmpty();
	}
	void RemoveAll();
	void Insert(CFGFilter* pFGF, int group, bool exactmatch = false, bool autodelete = true);

	POSITION GetHeadPosition();
	CFGFilter* GetNext(POSITION& pos) const;
private:
	struct filter_t {
		int index;
		CFGFilter* pFGF;
		int group;
		bool exactmatch, autodelete;
	};
	static int filter_cmp(const void* a, const void* b);
	CAtlList<filter_t> m_filters;
	CAtlList<CFGFilter*> m_sortedfilters;

};
